package com.google.code.gaeapptest.junit;

import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.fail;

import java.io.BufferedReader;
import java.nio.ByteBuffer;
import java.nio.channels.Channels;

import org.junit.Test;

import com.google.appengine.api.files.AppEngineFile;
import com.google.appengine.api.files.FileReadChannel;
import com.google.appengine.api.files.FileService;
import com.google.appengine.api.files.FileServiceFactory;
import com.google.appengine.api.files.FileWriteChannel;
import com.google.appengine.api.files.GSFileOptions.GSFileOptionsBuilder;

// Before you can run these tests you must create the bucket apptest at:
// https://sandbox.google.com/storage
// http://commondatastorage.googleapis.com/apptest/my_object
// http://code.google.com/appengine/docs/java/googlestorage/overview.html
// http://code.google.com/appengine/docs/java/javadoc/com/google/appengine/api/files/FileService.html
// Warning: the cloud api is not supported by Google App accounts!!!

public class FileTests extends BaseTest implements GaeTest {
	private static String TEST_TYPE = "File";
	private static String TEST_DATA = "Some test data";

	@Test
	public void all() throws Exception {
		long start = System.currentTimeMillis();
		createFile();
		updateFile();
		readFile();
		long elapsed = System.currentTimeMillis() - start;
		saveResult(TEST_TYPE, elapsed, "OK");
	}

	@Test
	public void createFile() throws Exception {
		long elapsed = -1L;
		String msg = "UNKNOWN";
		try {
			FileService fileService = FileServiceFactory.getFileService();
			GSFileOptionsBuilder optionsBuilder = new GSFileOptionsBuilder()
					.setBucket("apptest").setKey("my_object")
					.setAcl("public-read");
			long start = System.currentTimeMillis();
			AppEngineFile writableFile = fileService
					.createNewGSFile(optionsBuilder.build());
			elapsed = System.currentTimeMillis() - start;
			assertThat(writableFile, is(notNullValue()));
			if (writableFile != null) {
				msg = "OK";
			} else {
				msg = "ERR writableFile:" + writableFile;
				elapsed = -1;
				fail("unable to create");
			}
		} catch (Exception e) {
			msg = "Err:" + e.getMessage();
			fail("Err:" + e.getMessage());
			e.printStackTrace();
		} finally {
			saveResult(TEST_TYPE, elapsed, msg);
		}
	}

	@Test
	public void updateFile() throws Exception {
		long elapsed = -1L;
		String msg = "UNKNOWN";
		try {
			FileService fileService = FileServiceFactory.getFileService();
			GSFileOptionsBuilder optionsBuilder = new GSFileOptionsBuilder()
					.setBucket("apptest").setKey("my_object")
					.setAcl("public-read").setMimeType("text/html");
			AppEngineFile writableFile = fileService
					.createNewGSFile(optionsBuilder.build());
			// Save the file path
			String path = writableFile.getFullPath();
			// Lock the file so no one else can access it at the same time
			boolean lockForWrite = true;
			writableFile = new AppEngineFile(path);
			long start = System.currentTimeMillis();
			FileWriteChannel writeChannel = fileService.openWriteChannel(
					writableFile, lockForWrite);
			writeChannel.write(ByteBuffer.wrap(TEST_DATA.getBytes()));
			writeChannel.closeFinally();
			elapsed = System.currentTimeMillis() - start;
			AppEngineFile readableFile = new AppEngineFile(path);

			FileReadChannel readChannel = fileService.openReadChannel(
					readableFile, false);
			BufferedReader reader = new BufferedReader(Channels.newReader(
					readChannel, "UTF"));
			String line = reader.readLine();
			readChannel.close();
			if (line != null && line.startsWith(TEST_DATA)) {
				msg = "OK";
			} else {
				msg = "ERR line:" + line;
				elapsed = -1;
				fail("unable to update");
			}
		} catch (Exception e) {
			msg = "Err:" + e.getMessage();
			fail("Err:" + e.getMessage());
			e.printStackTrace();
		} finally {
			saveResult(TEST_TYPE, elapsed, msg);
		}
	}

	@Test
	public void readFile() throws Exception {
		long elapsed = -1L;
		String msg = "UNKNOWN";
		try {
			FileService fileService = FileServiceFactory.getFileService();
			GSFileOptionsBuilder optionsBuilder = new GSFileOptionsBuilder()
					.setBucket("apptest").setKey("my_object")
					.setAcl("public-read").setMimeType("text/html");
			AppEngineFile writableFile = fileService
					.createNewGSFile(optionsBuilder.build());
			// Save the file path
			String path = writableFile.getFullPath();
			// Write data
			writableFile = new AppEngineFile(path);
			FileWriteChannel writeChannel = fileService.openWriteChannel(
					writableFile, true);
			writeChannel.write(ByteBuffer.wrap(TEST_DATA.getBytes()));
			writeChannel.closeFinally();

			boolean lockForRead = false;
			String filename = path; // "/gs/apptest/my_object";
			AppEngineFile readableFile = new AppEngineFile(filename);
			long start = System.currentTimeMillis();
			FileReadChannel readChannel = fileService.openReadChannel(
					readableFile, lockForRead);
			BufferedReader reader = new BufferedReader(Channels.newReader(
					readChannel, "UTF"));
			String line = reader.readLine();
			readChannel.close();
			elapsed = System.currentTimeMillis() - start;
			if (line != null && line.startsWith(TEST_DATA)) {
				msg = "OK";
			} else {
				msg = "ERR line:" + line;
				elapsed = -1;
				fail("unable to read");
			}
		} catch (Exception e) {
			msg = "Err:" + e.getMessage();
			fail("Err:" + e.getMessage());
			e.printStackTrace();
		} finally {
			saveResult(TEST_TYPE, elapsed, msg);
		}
	}

}
